//
// The graphics engine GLScene https://github.com/glscene
//
unit Formats.DXTC;

(*
  DXTC (also S3TC) decoding.
  Adapted from DevIL image library (http://openil.sourceforge.net)
*)

interface

{$I GLS.Scene.inc}
{$Z4}  // Minimum enum size = dword

uses
  Winapi.OpenGL,
  Winapi.OpenGLext,
  System.SysUtils,

  GLS.TextureFormat;

const
  DDSD_CAPS = $00000001;
  DDSD_HEIGHT = $00000002;
  DDSD_WIDTH = $00000004;
  DDSD_PITCH = $00000008;
  DDSD_PIXELFORMAT = $00001000;
  DDSD_MIPMAPCOUNT = $00020000;
  DDSD_LINEARSIZE = $00080000;
  DDSD_DEPTH = $00800000;

  DDPF_ALPHAPIXELS = $00000001;
  DDPF_A = $00000002;
  DDPF_FOURCC = $00000004;
  DDPF_RGB = $00000040;
  DDPF_RGBA = $00000041;
  DDPF_L = $00020000;
  DDPF_LA = $00020001;

  DDSCAPS_COMPLEX = $00000008;
  DDSCAPS_TEXTURE = $00001000;
  DDSCAPS_MIPMAP = $00400000;

  DDSCAPS2_CUBEMAP = $00000200;
  DDSCAPS2_CUBEMAP_POSITIVEX = $00000400;
  DDSCAPS2_CUBEMAP_NEGATIVEX = $00000800;
  DDSCAPS2_CUBEMAP_POSITIVEY = $00001000;
  DDSCAPS2_CUBEMAP_NEGATIVEY = $00002000;
  DDSCAPS2_CUBEMAP_POSITIVEZ = $00004000;
  DDSCAPS2_CUBEMAP_NEGATIVEZ = $00008000;
  DDSCAPS2_VOLUME = $00200000;

type
  TDDPIXELFORMAT = record
    dwSize, dwFlags, dwFourCC, dwRGBBitCount, dwRBitMask, dwGBitMask, dwBBitMask,
      dwRGBAlphaBitMask: Cardinal;
  end;

  TDDSURFACEDESC2 = record
    dwSize, dwFlags, dwHeight, dwWidth, dwPitchOrLinearSize,
    (* The number of bytes per scan line in an
      uncompressed texture; the total number of bytes
      in the top level texture for a compressed texture. *)
    dwDepth, dwMipMapCount: Cardinal;
    dwReserved1: array [0 .. 10] of Cardinal;
    ddpf: TDDPIXELFORMAT;
    dwCaps, dwCaps2, dwCaps3, dwCaps4: Cardinal;
    dwReserved2: Cardinal;
  end;

  TDDSHeader = record
    Magic: Cardinal;
    SurfaceFormat: TDDSURFACEDESC2;
  end;

  DXTColBlock = record
    col0: Word;
    col1: Word;
    row: array [0 .. 3] of Byte;
  end;

  PDXTColBlock = ^DXTColBlock;

  DXT3AlphaBlock = record
    row: array [0 .. 3] of Word;
  end;

  PDXT3AlphaBlock = ^DXT3AlphaBlock;

  DXT5AlphaBlock = record
    alpha0: Byte;
    alpha1: Byte;
    row: array [0 .. 5] of Byte;
  end;

  PDXT5AlphaBlock = ^DXT5AlphaBlock;

const
  // TDXGI_FORMAT =
  // (
  DXGI_FORMAT_FORCE_UINT = -1;
  DXGI_FORMAT_UNKNOWN = 0;
  DXGI_FORMAT_R32G32B32A32_TYPELESS = 1;
  DXGI_FORMAT_R32G32B32A32_FLOAT = 2;
  DXGI_FORMAT_R32G32B32A32_UINT = 3;
  DXGI_FORMAT_R32G32B32A32_SINT = 4;
  DXGI_FORMAT_R32G32B32_TYPELESS = 5;
  DXGI_FORMAT_R32G32B32_FLOAT = 6;
  DXGI_FORMAT_R32G32B32_UINT = 7;
  DXGI_FORMAT_R32G32B32_SINT = 8;
  DXGI_FORMAT_R16G16B16A16_TYPELESS = 9;
  DXGI_FORMAT_R16G16B16A16_FLOAT = 10;
  DXGI_FORMAT_R16G16B16A16_UNORM = 11;
  DXGI_FORMAT_R16G16B16A16_UINT = 12;
  DXGI_FORMAT_R16G16B16A16_SNORM = 13;
  DXGI_FORMAT_R16G16B16A16_SINT = 14;
  DXGI_FORMAT_R32G32_TYPELESS = 15;
  DXGI_FORMAT_R32G32_FLOAT = 16;
  DXGI_FORMAT_R32G32_UINT = 17;
  DXGI_FORMAT_R32G32_SINT = 18;
  DXGI_FORMAT_R32G8X24_TYPELESS = 19;
  DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20;
  DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21;
  DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22;
  DXGI_FORMAT_R10G10B10A2_TYPELESS = 23;
  DXGI_FORMAT_R10G10B10A2_UNORM = 24;
  DXGI_FORMAT_R10G10B10A2_UINT = 25;
  DXGI_FORMAT_R11G11B10_FLOAT = 26;
  DXGI_FORMAT_R8G8B8A8_TYPELESS = 27;
  DXGI_FORMAT_R8G8B8A8_UNORM = 28;
  DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29;
  DXGI_FORMAT_R8G8B8A8_UINT = 30;
  DXGI_FORMAT_R8G8B8A8_SNORM = 31;
  DXGI_FORMAT_R8G8B8A8_SINT = 32;
  DXGI_FORMAT_R16G16_TYPELESS = 33;
  DXGI_FORMAT_R16G16_FLOAT = 34;
  DXGI_FORMAT_R16G16_UNORM = 35;
  DXGI_FORMAT_R16G16_UINT = 36;
  DXGI_FORMAT_R16G16_SNORM = 37;
  DXGI_FORMAT_R16G16_SINT = 38;
  DXGI_FORMAT_R32_TYPELESS = 39;
  DXGI_FORMAT_D32_FLOAT = 40;
  DXGI_FORMAT_R32_FLOAT = 41;
  DXGI_FORMAT_R32_UINT = 42;
  DXGI_FORMAT_R32_SINT = 43;
  DXGI_FORMAT_R24G8_TYPELESS = 44;
  DXGI_FORMAT_D24_UNORM_S8_UINT = 45;
  DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46;
  DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47;
  DXGI_FORMAT_R8G8_TYPELESS = 48;
  DXGI_FORMAT_R8G8_UNORM = 49;
  DXGI_FORMAT_R8G8_UINT = 50;
  DXGI_FORMAT_R8G8_SNORM = 51;
  DXGI_FORMAT_R8G8_SINT = 52;
  DXGI_FORMAT_R16_TYPELESS = 53;
  DXGI_FORMAT_R16_FLOAT = 54;
  DXGI_FORMAT_D16_UNORM = 55;
  DXGI_FORMAT_R16_UNORM = 56;
  DXGI_FORMAT_R16_UINT = 57;
  DXGI_FORMAT_R16_SNORM = 58;
  DXGI_FORMAT_R16_SINT = 59;
  DXGI_FORMAT_R8_TYPELESS = 60;
  DXGI_FORMAT_R8_UNORM = 61;
  DXGI_FORMAT_R8_UINT = 62;
  DXGI_FORMAT_R8_SNORM = 63;
  DXGI_FORMAT_R8_SINT = 64;
  DXGI_FORMAT_A8_UNORM = 65;
  DXGI_FORMAT_R1_UNORM = 66;
  DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67;
  DXGI_FORMAT_R8G8_B8G8_UNORM = 68;
  DXGI_FORMAT_G8R8_G8B8_UNORM = 69;
  DXGI_FORMAT_BC1_TYPELESS = 70;
  DXGI_FORMAT_BC1_UNORM = 71;
  DXGI_FORMAT_BC1_UNORM_SRGB = 72;
  DXGI_FORMAT_BC2_TYPELESS = 73;
  DXGI_FORMAT_BC2_UNORM = 74;
  DXGI_FORMAT_BC2_UNORM_SRGB = 75;
  DXGI_FORMAT_BC3_TYPELESS = 76;
  DXGI_FORMAT_BC3_UNORM = 77;
  DXGI_FORMAT_BC3_UNORM_SRGB = 78;
  DXGI_FORMAT_BC4_TYPELESS = 79;
  DXGI_FORMAT_BC4_UNORM = 80;
  DXGI_FORMAT_BC4_SNORM = 81;
  DXGI_FORMAT_BC5_TYPELESS = 82;
  DXGI_FORMAT_BC5_UNORM = 83;
  DXGI_FORMAT_BC5_SNORM = 84;
  DXGI_FORMAT_B5G6R5_UNORM = 85;
  DXGI_FORMAT_B5G5R5A1_UNORM = 86;
  DXGI_FORMAT_B8G8R8A8_UNORM = 87;
  DXGI_FORMAT_B8G8R8X8_UNORM = 88;
  DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89;
  DXGI_FORMAT_B8G8R8A8_TYPELESS = 90;
  DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91;
  DXGI_FORMAT_B8G8R8X8_TYPELESS = 92;
  DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93;
  DXGI_FORMAT_BC6H_TYPELESS = 94;
  DXGI_FORMAT_BC6H_UF16 = 95;
  DXGI_FORMAT_BC6H_SF16 = 96;
  DXGI_FORMAT_BC7_TYPELESS = 97;
  DXGI_FORMAT_BC7_UNORM = 98;
  DXGI_FORMAT_BC7_UNORM_SRGB = 99;
  // );

  // TD3D11_RESOURCE_DIMENSION =
  // (
  D3D11_RESOURCE_DIMENSION_UNKNOWN = 0;
  D3D11_RESOURCE_DIMENSION_BUFFER = 1;
  D3D11_RESOURCE_DIMENSION_TEXTURE1D = 2;
  D3D11_RESOURCE_DIMENSION_TEXTURE2D = 3;
  D3D11_RESOURCE_DIMENSION_TEXTURE3D = 4;
  // );

type
  TDDS_HEADER_DXT10 = record
    dxgiFormat: Integer; // TDXGI_FORMAT;
    resourceDimension: Integer; // TD3D11_RESOURCE_DIMENSION;
    miscFlag: Cardinal;
    arraySize: Cardinal;
    reserved: Cardinal;
  end;

  TFOURCC = array [0 .. 3] of AnsiChar;

const
  FOURCC_UNKNOWN = 0;
  FOURCC_R8G8B8 = 20;
  FOURCC_A8R8G8B8 = 21;
  FOURCC_X8R8G8B8 = 22;
  FOURCC_R5G6B5 = 23;
  FOURCC_X1R5G5B5 = 24;
  FOURCC_A1R5G5B5 = 25;
  FOURCC_A4R4G4B4 = 26;
  FOURCC_R3G3B2 = 27;
  FOURCC_A8 = 28;
  FOURCC_A8R3G3B2 = 29;
  FOURCC_X4R4G4B4 = 30;
  FOURCC_A2B10G10R10 = 31;
  FOURCC_A8B8G8R8 = 32;
  FOURCC_X8B8G8R8 = 33;
  FOURCC_G16R16 = 34;
  FOURCC_A2R10G10B10 = 35;
  FOURCC_A16B16G16R16 = 36;

  FOURCC_L8 = 50;
  FOURCC_A8L8 = 51;
  FOURCC_A4L4 = 52;
  FOURCC_DXT1 = $31545844;
  FOURCC_DXT2 = $32545844;
  FOURCC_DXT3 = $33545844;
  FOURCC_DXT4 = $34545844;
  FOURCC_DXT5 = $35545844;
  FOURCC_ATI1 = $31495441;
  FOURCC_ATI2 = $32495441;

  FOURCC_D16_LOCKABLE = 70;
  FOURCC_D32 = 71;
  FOURCC_D24X8 = 77;
  FOURCC_D16 = 80;

  FOURCC_D32F_LOCKABLE = 82;

  FOURCC_L16 = 81;

  // Floating point surface formats

  // s10e5 formats (16-bits per channel)
  FOURCC_R16F = 111;
  FOURCC_G16R16F = 112;
  FOURCC_A16B16G16R16F = 113;

  // IEEE s23e8 formats (32-bits per channel)
  FOURCC_R32F = 114;
  FOURCC_G32R32F = 115;
  FOURCC_A32B32G32R32F = 116;

  // DX10 header indicator
  FOURCC_DX10 = $47495844;

type
  TGLImageDataFormat = record
    ColorFlag: Cardinal;
    RBits, GBits, BBits, ABits: Cardinal;
    colorFormat: Cardinal;
    TexFormat: TGLinternalFormat;
    dType: Cardinal;
  end;

const
  cImageDataFormat8bits: array [0 .. 3] of TGLImageDataFormat = ((ColorFlag: DDPF_RGB; RBits: $E0;
    GBits: $1C; BBits: $03; ABits: $00; colorFormat: GL_RGB; TexFormat: tfR3_G3_B2;
    dType: GL_UNSIGNED_BYTE_3_3_2),

    (ColorFlag: DDPF_LA; RBits: $0F; GBits: $00; BBits: $00; ABits: $F0;
    colorFormat: GL_LUMINANCE_ALPHA; TexFormat: tfLUMINANCE4_ALPHA4; dType: GL_UNSIGNED_BYTE),

    (ColorFlag: DDPF_A; RBits: $00; GBits: $00; BBits: $00; ABits: $FF; colorFormat: GL_ALPHA;
    TexFormat: tfALPHA8; dType: GL_UNSIGNED_BYTE),

    (ColorFlag: DDPF_L; RBits: $FF; GBits: $00; BBits: $00; ABits: $00; colorFormat: GL_LUMINANCE;
    TexFormat: tfLUMINANCE8; dType: GL_UNSIGNED_BYTE));

  cImageDataFormat16bits: array [0 .. 4] of TGLImageDataFormat = ((ColorFlag: DDPF_RGBA;
    RBits: $0F00; GBits: $F0; BBits: $0F; ABits: $F000; colorFormat: GL_BGRA; TexFormat: tfRGBA4;
    dType: GL_UNSIGNED_SHORT_4_4_4_4_REV),

    (ColorFlag: DDPF_RGB; RBits: $F800; GBits: $07E0; BBits: $1F; ABits: $00; colorFormat: GL_RGB;
    TexFormat: tfRGB5; dType: GL_UNSIGNED_SHORT_5_6_5),

    (ColorFlag: DDPF_L; RBits: $FFFF; GBits: $00; BBits: $00; ABits: $00; colorFormat: GL_LUMINANCE;
    TexFormat: tfLUMINANCE16; dType: GL_UNSIGNED_SHORT),

    (ColorFlag: DDPF_LA; RBits: $FF; GBits: $00; BBits: $00; ABits: $FF00;
    colorFormat: GL_LUMINANCE_ALPHA; TexFormat: tfLUMINANCE8_ALPHA8; dType: GL_UNSIGNED_BYTE),

    (ColorFlag: DDPF_RGBA; RBits: $7C00; GBits: $03E0; BBits: $1F; ABits: $8000;
    colorFormat: GL_BGRA; TexFormat: tfRGB5_A1; dType: GL_UNSIGNED_SHORT_1_5_5_5_REV));

  cImageDataFormat24bits: array [0 .. 0] of TGLImageDataFormat = ((ColorFlag: DDPF_RGB;
    RBits: $FF0000; GBits: $FF00; BBits: $FF; ABits: $00; colorFormat: GL_BGR; TexFormat: tfRGB8;
    dType: GL_UNSIGNED_BYTE));

  cImageDataFormat32bits: array [0 .. 6] of TGLImageDataFormat = ((ColorFlag: DDPF_RGBA; RBits: $FF;
    GBits: $FF00; BBits: $FF0000; ABits: $FF000000; colorFormat: GL_RGBA; TexFormat: tfRGBA8;
    dType: GL_UNSIGNED_BYTE),

    (ColorFlag: DDPF_RGBA; RBits: $FF0000; GBits: $FF00; BBits: $FF; ABits: $FF000000;
    colorFormat: GL_BGRA; TexFormat: tfRGBA8; dType: GL_UNSIGNED_BYTE),

    (ColorFlag: DDPF_RGBA; RBits: $3FF00000; GBits: $0FFC00; BBits: $03FF; ABits: $0C0000000;
    colorFormat: GL_RGBA; TexFormat: tfRGB10_A2; dType: GL_UNSIGNED_INT_2_10_10_10_REV),

    (ColorFlag: DDPF_RGBA; RBits: $03FF; GBits: $FFC00; BBits: $3FF00000; ABits: $C0000000;
    colorFormat: GL_BGRA; TexFormat: tfRGB10_A2; dType: GL_UNSIGNED_INT_2_10_10_10_REV),

    (ColorFlag: DDPF_RGBA; RBits: $FF0000; GBits: $FF00; BBits: $FF; ABits: $FF000000;
    colorFormat: GL_BGRA; TexFormat: tfRGB8; dType: GL_UNSIGNED_INT_8_8_8_8),

    (ColorFlag: DDPF_RGBA; RBits: $FF; GBits: $FF00; BBits: $FF0000; ABits: $FF000000;
    colorFormat: GL_RGBA; TexFormat: tfRGB8; dType: GL_UNSIGNED_INT_8_8_8_8),

    (ColorFlag: DDPF_RGB; RBits: $FFFF; GBits: $FFFF0000; BBits: $00; ABits: $00;
    colorFormat: GL_RG; TexFormat: tfRG16; dType: GL_UNSIGNED_SHORT));

procedure DecodeDXT1toBitmap32(encData, decData: PByteArray; w, h: Integer; var trans: Boolean);
procedure DecodeDXT3toBitmap32(encData, decData: PByteArray; w, h: Integer);
procedure DecodeDXT5toBitmap32(encData, decData: PByteArray; w, h: Integer);
procedure flip_blocks_dxtc1(data: PGLubyte; numBlocks: Integer);
procedure flip_blocks_dxtc3(data: PGLubyte; numBlocks: Integer);
procedure flip_blocks_dxtc5(data: PGLubyte; numBlocks: Integer);
procedure flip_dxt5_alpha(block: PDXT5AlphaBlock);

function DDSHeaderToGLEnum(const DX9header: TDDSHeader; const DX11header: TDDS_HEADER_DXT10;
  const useDX11: Boolean; out iFormat: TGLinternalFormat; out colorFormat: Cardinal;
  out dataType: Cardinal; out bpe: Integer): Boolean;

function GLEnumToDDSHeader(var DX9header: TDDSHeader; var DX11header: TDDS_HEADER_DXT10;
  const useDX11: Boolean; const iFormat: TGLinternalFormat; const colorFormat: Cardinal;
  const dataType: Cardinal; const bpe: Integer): Boolean;

function FindDDSCompatibleDataFormat(const iFormat: TGLinternalFormat; out colorFormat: Cardinal;
  out dataType: Cardinal): Boolean;

// --------------------------------------------------
implementation
// --------------------------------------------------

procedure DecodeColor565(col: Word; out r, g, b: Byte);
begin
  r := col and $1F;
  g := (col shr 5) and $3F;
  b := (col shr 11) and $1F;
end;

procedure DecodeDXT1toBitmap32(encData, decData: PByteArray; w, h: Integer; var trans: Boolean);
var
  x, y, i, j, k, select: Integer;
  col0, col1: Word;
  colors: array [0 .. 3] of array [0 .. 3] of Byte;
  bitmask: Cardinal;
  temp: PGLubyte;
  r0, g0, b0, r1, g1, b1: Byte;
begin
  trans := False;

  if not(Assigned(encData) and Assigned(decData)) then
    exit;

  temp := PGLubyte(encData);
  for y := 0 to (h div 4) - 1 do
  begin
    for x := 0 to (w div 4) - 1 do
    begin
      col0 := PWord(temp)^;
      Inc(temp, 2);
      col1 := PWord(temp)^;
      Inc(temp, 2);
      bitmask := PCardinal(temp)^;
      Inc(temp, 4);

      DecodeColor565(col0, r0, g0, b0);
      DecodeColor565(col1, r1, g1, b1);

      colors[0][0] := r0 shl 3;
      colors[0][1] := g0 shl 2;
      colors[0][2] := b0 shl 3;
      colors[0][3] := $FF;
      colors[1][0] := r1 shl 3;
      colors[1][1] := g1 shl 2;
      colors[1][2] := b1 shl 3;
      colors[1][3] := $FF;

      if col0 > col1 then
      begin
        colors[2][0] := (2 * colors[0][0] + colors[1][0] + 1) div 3;
        colors[2][1] := (2 * colors[0][1] + colors[1][1] + 1) div 3;
        colors[2][2] := (2 * colors[0][2] + colors[1][2] + 1) div 3;
        colors[2][3] := $FF;
        colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
        colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
        colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
        colors[3][3] := $FF;
      end
      else
      begin
        trans := True;
        colors[2][0] := (colors[0][0] + colors[1][0]) div 2;
        colors[2][1] := (colors[0][1] + colors[1][1]) div 2;
        colors[2][2] := (colors[0][2] + colors[1][2]) div 2;
        colors[2][3] := $FF;
        colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
        colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
        colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
        colors[3][3] := 0;
      end;

      k := 0;
      for j := 0 to 3 do
      begin
        for i := 0 to 3 do
        begin
          select := (bitmask and (3 shl (k * 2))) shr (k * 2);
          if ((4 * x + i) < w) and ((4 * y + j) < h) then
            PCardinal(@decData[((4 * y + j) * w + (4 * x + i)) * 4])^ := Cardinal(colors[select]);
          Inc(k);
        end;
      end;

    end;
  end;
end;

procedure DecodeDXT3toBitmap32(encData, decData: PByteArray; w, h: Integer);
var
  x, y, i, j, k, select: Integer;
  col0, col1, wrd: Word;
  colors: array [0 .. 3] of array [0 .. 3] of Byte;
  bitmask, offset: Cardinal;
  temp: PGLubyte;
  r0, g0, b0, r1, g1, b1: Byte;
  alpha: array [0 .. 3] of Word;
begin
  if not(Assigned(encData) and Assigned(decData)) then
    exit;

  temp := PGLubyte(encData);
  for y := 0 to (h div 4) - 1 do
  begin
    for x := 0 to (w div 4) - 1 do
    begin
      alpha[0] := PWord(temp)^;
      Inc(temp, 2);
      alpha[1] := PWord(temp)^;
      Inc(temp, 2);
      alpha[2] := PWord(temp)^;
      Inc(temp, 2);
      alpha[3] := PWord(temp)^;
      Inc(temp, 2);
      col0 := PWord(temp)^;
      Inc(temp, 2);
      col1 := PWord(temp)^;
      Inc(temp, 2);
      bitmask := PCardinal(temp)^;
      Inc(temp, 4);

      DecodeColor565(col0, r0, g0, b0);
      DecodeColor565(col1, r1, g1, b1);

      colors[0][0] := r0 shl 3;
      colors[0][1] := g0 shl 2;
      colors[0][2] := b0 shl 3;
      colors[0][3] := $FF;
      colors[1][0] := r1 shl 3;
      colors[1][1] := g1 shl 2;
      colors[1][2] := b1 shl 3;
      colors[1][3] := $FF;
      colors[2][0] := (2 * colors[0][0] + colors[1][0] + 1) div 3;
      colors[2][1] := (2 * colors[0][1] + colors[1][1] + 1) div 3;
      colors[2][2] := (2 * colors[0][2] + colors[1][2] + 1) div 3;
      colors[2][3] := $FF;
      colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
      colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
      colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
      colors[3][3] := $FF;

      k := 0;
      for j := 0 to 3 do
      begin
        for i := 0 to 3 do
        begin
          select := (bitmask and (3 shl (k * 2))) shr (k * 2);
          if ((4 * x + i) < w) and ((4 * y + j) < h) then
            PCardinal(@decData[((4 * y + j) * w + (4 * x + i)) * 4])^ := Cardinal(colors[select]);
          Inc(k);
        end;
      end;

      for j := 0 to 3 do
      begin
        wrd := alpha[j];
        for i := 0 to 3 do
        begin
          if (((4 * x + i) < w) and ((4 * y + j) < h)) then
          begin
            offset := ((4 * y + j) * w + (4 * x + i)) * 4 + 3;
            decData[offset] := wrd and $0F;
            decData[offset] := decData[offset] or (decData[offset] shl 4);
          end;
          wrd := wrd shr 4;
        end;
      end;

    end;
  end;
end;

procedure DecodeDXT5toBitmap32(encData, decData: PByteArray; w, h: Integer);
var
  x, y, i, j, k, select: Integer;
  col0, col1: Word;
  colors: array [0 .. 3] of array [0 .. 3] of Byte;
  bits, bitmask, offset: Cardinal;
  temp, alphamask: PGLubyte;
  r0, g0, b0, r1, g1, b1: Byte;
  alphas: array [0 .. 7] of Byte;
begin
  if not(Assigned(encData) and Assigned(decData)) then
    exit;

  temp := PGLubyte(encData);
  for y := 0 to (h div 4) - 1 do
  begin
    for x := 0 to (w div 4) - 1 do
    begin
      alphas[0] := temp^;
      Inc(temp);
      alphas[1] := temp^;
      Inc(temp);
      alphamask := temp;
      Inc(temp, 6);
      col0 := PWord(temp)^;
      Inc(temp, 2);
      col1 := PWord(temp)^;
      Inc(temp, 2);
      bitmask := PCardinal(temp)^;
      Inc(temp, 4);

      DecodeColor565(col0, r0, g0, b0);
      DecodeColor565(col1, r1, g1, b1);

      colors[0][0] := r0 shl 3;
      colors[0][1] := g0 shl 2;
      colors[0][2] := b0 shl 3;
      colors[0][3] := $FF;
      colors[1][0] := r1 shl 3;
      colors[1][1] := g1 shl 2;
      colors[1][2] := b1 shl 3;
      colors[1][3] := $FF;
      colors[2][0] := (2 * colors[0][0] + colors[1][0] + 1) div 3;
      colors[2][1] := (2 * colors[0][1] + colors[1][1] + 1) div 3;
      colors[2][2] := (2 * colors[0][2] + colors[1][2] + 1) div 3;
      colors[2][3] := $FF;
      colors[3][0] := (colors[0][0] + 2 * colors[1][0] + 1) div 3;
      colors[3][1] := (colors[0][1] + 2 * colors[1][1] + 1) div 3;
      colors[3][2] := (colors[0][2] + 2 * colors[1][2] + 1) div 3;
      colors[3][3] := $FF;

      k := 0;
      for j := 0 to 3 do
      begin
        for i := 0 to 3 do
        begin
          select := (bitmask and (3 shl (k * 2))) shr (k * 2);
          if ((4 * x + i) < w) and ((4 * y + j) < h) then
            PCardinal(@decData[((4 * y + j) * w + (4 * x + i)) * 4])^ := Cardinal(colors[select]);
          Inc(k);
        end;
      end;

      if (alphas[0] > alphas[1]) then
      begin
        alphas[2] := (6 * alphas[0] + 1 * alphas[1] + 3) div 7;
        alphas[3] := (5 * alphas[0] + 2 * alphas[1] + 3) div 7;
        alphas[4] := (4 * alphas[0] + 3 * alphas[1] + 3) div 7;
        alphas[5] := (3 * alphas[0] + 4 * alphas[1] + 3) div 7;
        alphas[6] := (2 * alphas[0] + 5 * alphas[1] + 3) div 7;
        alphas[7] := (1 * alphas[0] + 6 * alphas[1] + 3) div 7;
      end
      else
      begin
        alphas[2] := (4 * alphas[0] + 1 * alphas[1] + 2) div 5;
        alphas[3] := (3 * alphas[0] + 2 * alphas[1] + 2) div 5;
        alphas[4] := (2 * alphas[0] + 3 * alphas[1] + 2) div 5;
        alphas[5] := (1 * alphas[0] + 4 * alphas[1] + 2) div 5;
        alphas[6] := 0;
        alphas[7] := $FF;
      end;

      bits := PCardinal(alphamask)^;
      for j := 0 to 1 do
      begin
        for i := 0 to 3 do
        begin
          if (((4 * x + i) < w) and ((4 * y + j) < h)) then
          begin
            offset := ((4 * y + j) * w + (4 * x + i)) * 4 + 3;
            decData[offset] := alphas[bits and 7];
          end;
          bits := bits shr 3;
        end;
      end;

      Inc(alphamask, 3);
      bits := PCardinal(alphamask)^;
      for j := 2 to 3 do
      begin
        for i := 0 to 3 do
        begin
          if (((4 * x + i) < w) and ((4 * y + j) < h)) then
          begin
            offset := ((4 * y + j) * w + (4 * x + i)) * 4 + 3;
            decData[offset] := alphas[bits and 7];
          end;
          bits := bits shr 3;
        end;
      end;

    end;
  end;
end;

//==============================================================
procedure flip_blocks_dxtc1(data: PGLubyte; numBlocks: Integer);
var
  curblock: PDXTColBlock;
  temp: Byte;
  i: Integer;
begin
  curblock := PDXTColBlock(data);
  for i := 0 to numBlocks - 1 do
  begin
    temp := curblock.row[0];
    curblock.row[0] := curblock.row[3];
    curblock.row[3] := temp;
    temp := curblock.row[1];
    curblock.row[1] := curblock.row[2];
    curblock.row[2] := temp;

    Inc(curblock);
  end;
end;

// flip a DXT3 color block
//===============================================================
procedure flip_blocks_dxtc3(data: PGLubyte; numBlocks: Integer);
var
  curblock: PDXTColBlock;
  alphablock: PDXT3AlphaBlock;
  tempS: Word;
  tempB: Byte;
  i: Integer;
begin
  curblock := PDXTColBlock(data);
  for i := 0 to numBlocks - 1 do
  begin
    alphablock := PDXT3AlphaBlock(curblock);

    tempS := alphablock.row[0];
    alphablock.row[0] := alphablock.row[3];
    alphablock.row[3] := tempS;
    tempS := alphablock.row[1];
    alphablock.row[1] := alphablock.row[2];
    alphablock.row[2] := tempS;

    Inc(curblock);

    tempB := curblock.row[0];
    curblock.row[0] := curblock.row[3];
    curblock.row[3] := tempB;
    tempB := curblock.row[1];
    curblock.row[1] := curblock.row[2];
    curblock.row[2] := tempB;

    Inc(curblock);
  end;
end;

//=================================================
procedure flip_dxt5_alpha(block: PDXT5AlphaBlock);
const
  mask = $00000007; // bits = 00 00 01 11
var
  GBits: array [0 .. 3, 0 .. 3] of Byte;
  bits: Integer;
begin
  bits := 0;
  Move(block.row[0], bits, sizeof(Byte) * 3);

  GBits[0][0] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[0][1] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[0][2] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[0][3] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[1][0] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[1][1] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[1][2] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[1][3] := Byte(bits and mask);

  bits := 0;
  Move(block.row[3], bits, sizeof(Byte) * 3);

  GBits[2][0] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[2][1] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[2][2] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[2][3] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[3][0] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[3][1] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[3][2] := Byte(bits and mask);
  bits := bits shr 3;
  GBits[3][3] := Byte(bits and mask);

  // clear existing alpha bits
  FillChar(block.row, sizeof(Byte) * 6, 0);

  bits := block.row[0] + block.row[1] * $100 + block.row[2] * $10000;

  bits := bits or (GBits[3][0] shl 0);
  bits := bits or (GBits[3][1] shl 3);
  bits := bits or (GBits[3][2] shl 6);
  bits := bits or (GBits[3][3] shl 9);

  bits := bits or (GBits[2][0] shl 12);
  bits := bits or (GBits[2][1] shl 15);
  bits := bits or (GBits[2][2] shl 18);
  bits := bits or (GBits[2][3] shl 21);

  block.row[0] := bits and $FF;
  block.row[1] := (bits shr 8) and $FF;
  block.row[2] := (bits shr 16) and $FF;

  bits := block.row[3] + block.row[4] * $100 + block.row[5] * $10000;

  bits := bits or (GBits[1][0] shl 0);
  bits := bits or (GBits[1][1] shl 3);
  bits := bits or (GBits[1][2] shl 6);
  bits := bits or (GBits[1][3] shl 9);

  bits := bits or (GBits[0][0] shl 12);
  bits := bits or (GBits[0][1] shl 15);
  bits := bits or (GBits[0][2] shl 18);
  bits := bits or (GBits[0][3] shl 21);

  block.row[3] := bits and $FF;
  block.row[4] := (bits shr 8) and $FF;
  block.row[5] := (bits shr 16) and $FF;
end;

//==============================================================
procedure flip_blocks_dxtc5(data: PGLubyte; numBlocks: Integer);
var
  curblock: PDXTColBlock;
  temp: Byte;
  i: Integer;
begin
  curblock := PDXTColBlock(data);
  for i := 0 to numBlocks - 1 do
  begin
    flip_dxt5_alpha(PDXT5AlphaBlock(curblock));
    Inc(curblock);
    temp := curblock.row[0];
    curblock.row[0] := curblock.row[3];
    curblock.row[3] := temp;
    temp := curblock.row[1];
    curblock.row[1] := curblock.row[2];
    curblock.row[2] := temp;
    Inc(curblock);
  end;
end;

function DDSHeaderToGLEnum(const DX9header: TDDSHeader; const DX11header: TDDS_HEADER_DXT10;
  const useDX11: Boolean; out iFormat: TGLinternalFormat; out colorFormat: Cardinal;
  out dataType: Cardinal; out bpe: Integer): Boolean;
var
  i: Integer;
begin
  Result := True;
  if useDX11 then
  begin
    Assert(False, 'DXGI images not supported.');
  end
  // Use DX9 formats
  else
  begin
    // figure out what the image format is
    if (DX9header.SurfaceFormat.ddpf.dwFlags and DDPF_FOURCC) <> 0 then
    begin
      case DX9header.SurfaceFormat.ddpf.dwFourCC of
        FOURCC_DXT1:
          begin
            colorFormat := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
            iFormat := tfCOMPRESSED_RGBA_S3TC_DXT1;
            dataType := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
            bpe := 8;
          end;
        FOURCC_DXT2, FOURCC_DXT3:
          begin
            colorFormat := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
            iFormat := tfCOMPRESSED_RGBA_S3TC_DXT3;
            dataType := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
            bpe := 16;
          end;
        FOURCC_DXT4, FOURCC_DXT5:
          begin
            colorFormat := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
            iFormat := tfCOMPRESSED_RGBA_S3TC_DXT5;
            dataType := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
            bpe := 16;
          end;
        FOURCC_ATI1:
          begin
            colorFormat := GL_COMPRESSED_RED_RGTC1;
            iFormat := tfCOMPRESSED_RED_RGTC1;
            dataType := GL_COMPRESSED_RED_RGTC1;
            bpe := 8;
          end;
        FOURCC_ATI2:
          begin
            colorFormat := GL_COMPRESSED_RG_RGTC2;
            iFormat := tfCOMPRESSED_RG_RGTC2;
            dataType := GL_COMPRESSED_RG_RGTC2;
            bpe := 16;
          end;
        FOURCC_R8G8B8:
          begin
            colorFormat := GL_BGR;
            iFormat := tfRGB8;
            dataType := GL_UNSIGNED_BYTE;
            bpe := 3;
          end;
        FOURCC_A8R8G8B8:
          begin
            colorFormat := GL_BGRA;
            iFormat := tfRGBA8;
            dataType := GL_UNSIGNED_BYTE;
            bpe := 4;
          end;
        FOURCC_X8R8G8B8:
          begin
            colorFormat := GL_BGRA;
            iFormat := tfRGB8;
            dataType := GL_UNSIGNED_INT_8_8_8_8;
            bpe := 4;
          end;
        FOURCC_R5G6B5:
          begin
            colorFormat := GL_RGB;
            iFormat := tfRGB5;
            dataType := GL_UNSIGNED_SHORT_5_6_5;
            bpe := 2;
          end;
        FOURCC_A8:
          begin
            colorFormat := GL_ALPHA;
            iFormat := tfALPHA8;
            dataType := GL_UNSIGNED_BYTE;
            bpe := 1;
          end;
        FOURCC_A2B10G10R10:
          begin
            colorFormat := GL_RGBA;
            iFormat := tfRGB10_A2;
            dataType := GL_UNSIGNED_INT_10_10_10_2;
            bpe := 4;
          end;
        FOURCC_A8B8G8R8:
          begin
            colorFormat := GL_RGBA;
            iFormat := tfRGBA8;
            dataType := GL_UNSIGNED_BYTE;
            bpe := 4;
          end;
        FOURCC_X8B8G8R8:
          begin
            colorFormat := GL_RGBA;
            iFormat := tfRGB8;
            dataType := GL_UNSIGNED_INT_8_8_8_8;
            bpe := 4;
          end;
        FOURCC_A2R10G10B10:
          begin
            colorFormat := GL_BGRA;
            iFormat := tfRGB10_A2;
            dataType := GL_UNSIGNED_INT_10_10_10_2;
            bpe := 4;
          end;
        FOURCC_A16B16G16R16:
          begin
            colorFormat := GL_RGBA;
            iFormat := tfR16G16B16A16;
            dataType := GL_UNSIGNED_SHORT;
            bpe := 8;
          end;
        FOURCC_L8:
          begin
            colorFormat := GL_LUMINANCE;
            iFormat := tfLUMINANCE8;
            dataType := GL_UNSIGNED_BYTE;
            bpe := 1;
          end;
        FOURCC_A8L8:
          begin
            colorFormat := GL_LUMINANCE_ALPHA;
            iFormat := tfLUMINANCE8_ALPHA8;
            dataType := GL_UNSIGNED_BYTE;
            bpe := 2;
          end;
        FOURCC_L16:
          begin
            colorFormat := GL_LUMINANCE;
            iFormat := tfLUMINANCE16;
            dataType := GL_UNSIGNED_SHORT;
            bpe := 2;
          end;
        FOURCC_R16F:
          begin
            colorFormat := GL_RED;
            iFormat := tfLUMINANCE_FLOAT16;
            dataType := GL_HALF_FLOAT_ARB;
            bpe := 2;
          end;
        FOURCC_A16B16G16R16F:
          begin
            colorFormat := GL_RGBA;
            iFormat := tfRGBA_FLOAT16;
            dataType := GL_HALF_FLOAT_ARB;
            bpe := 8;
          end;
        FOURCC_R32F:
          begin
            colorFormat := GL_RED;
            iFormat := tfLUMINANCE_FLOAT32;
            dataType := GL_FLOAT;
            bpe := 4;
          end;
        FOURCC_G16R16:
          begin
            colorFormat := GL_RG;
            iFormat := tfRG16;
            dataType := GL_UNSIGNED_SHORT;
            bpe := 4;
          end;
        FOURCC_G16R16F:
          begin
            colorFormat := GL_RG;
            iFormat := tfRG16F;
            dataType := GL_HALF_FLOAT;
            bpe := 4;
          end;
        FOURCC_G32R32F:
          begin
            colorFormat := GL_RG;
            iFormat := tfRG32F;
            dataType := GL_FLOAT;
            bpe := 8;
          end;
        FOURCC_UNKNOWN, FOURCC_X1R5G5B5, FOURCC_A1R5G5B5, FOURCC_A4R4G4B4, FOURCC_R3G3B2,
          FOURCC_A8R3G3B2, FOURCC_X4R4G4B4, FOURCC_A4L4, FOURCC_D16_LOCKABLE, FOURCC_D32,
          FOURCC_D24X8, FOURCC_D16, FOURCC_D32F_LOCKABLE:
          Result := False; // these are unsupported for now
      end; // of case
    end // not FOURCC

    else
      with DX9header.SurfaceFormat.ddpf do
        case dwRGBBitCount of
          8:
            begin
              for i := 0 to High(cImageDataFormat8bits) do
                if (cImageDataFormat8bits[i].ColorFlag = dwFlags) and
                  (cImageDataFormat8bits[i].RBits = dwRBitMask) and
                  (cImageDataFormat8bits[i].GBits = dwGBitMask) and
                  (cImageDataFormat8bits[i].BBits = dwBBitMask) and
                  (cImageDataFormat8bits[i].ABits = dwRGBAlphaBitMask) then
                begin
                  colorFormat := cImageDataFormat8bits[i].colorFormat;
                  iFormat := cImageDataFormat8bits[i].TexFormat;
                  dataType := cImageDataFormat8bits[i].dType;
                  Result := True;
                  Break;
                end;
              bpe := 1;
            end;
          16:
            begin
              for i := 0 to High(cImageDataFormat16bits) do
                if (cImageDataFormat16bits[i].ColorFlag = dwFlags) and
                  (cImageDataFormat16bits[i].RBits = dwRBitMask) and
                  (cImageDataFormat16bits[i].GBits = dwGBitMask) and
                  (cImageDataFormat16bits[i].BBits = dwBBitMask) and
                  (cImageDataFormat16bits[i].ABits = dwRGBAlphaBitMask) then
                begin
                  colorFormat := cImageDataFormat16bits[i].colorFormat;
                  iFormat := cImageDataFormat16bits[i].TexFormat;
                  dataType := cImageDataFormat16bits[i].dType;
                  Result := True;
                  Break;
                end;
              bpe := 2;
            end;
          24:
            begin
              for i := 0 to High(cImageDataFormat24bits) do
                if (cImageDataFormat24bits[i].ColorFlag = dwFlags) and
                  (cImageDataFormat24bits[i].RBits = dwRBitMask) and
                  (cImageDataFormat24bits[i].GBits = dwGBitMask) and
                  (cImageDataFormat24bits[i].BBits = dwBBitMask) and
                  (cImageDataFormat24bits[i].ABits = dwRGBAlphaBitMask) then
                begin
                  colorFormat := cImageDataFormat24bits[i].colorFormat;
                  iFormat := cImageDataFormat24bits[i].TexFormat;
                  dataType := cImageDataFormat24bits[i].dType;
                  Result := True;
                  Break;
                end;
              bpe := 3;
            end;
          32:
            begin
              for i := 0 to High(cImageDataFormat32bits) do
                if (cImageDataFormat32bits[i].ColorFlag = dwFlags) and
                  (cImageDataFormat32bits[i].RBits = dwRBitMask) and
                  (cImageDataFormat32bits[i].GBits = dwGBitMask) and
                  (cImageDataFormat32bits[i].BBits = dwBBitMask) and
                  (cImageDataFormat32bits[i].ABits = dwRGBAlphaBitMask) then
                begin
                  colorFormat := cImageDataFormat32bits[i].colorFormat;
                  iFormat := cImageDataFormat32bits[i].TexFormat;
                  dataType := cImageDataFormat32bits[i].dType;
                  Result := True;
                  Break;
                end;
              bpe := 4;
            end;
        else
          Result := False;
        end; // of case
  end;
end;

//-------------------------------------------------------------------------------------

function GLEnumToDDSHeader(var DX9header: TDDSHeader; var DX11header: TDDS_HEADER_DXT10;
  const useDX11: Boolean; const iFormat: TGLinternalFormat; const colorFormat: Cardinal;
  const dataType: Cardinal; const bpe: Integer): Boolean;
var
  i: Integer;
begin
  Result := True;
  if useDX11 then
  begin
    Assert(False, 'DXGI images not supported.');
  end;

  if IsCompressedFormat(iFormat) then
  begin
    with DX9header.SurfaceFormat.ddpf do
    begin
      dwFlags := DDPF_FOURCC;
      case iFormat of
        tfCOMPRESSED_RGB_S3TC_DXT1:
          dwFourCC := FOURCC_DXT1;
        tfCOMPRESSED_RGBA_S3TC_DXT1:
          dwFourCC := FOURCC_DXT1;
        tfCOMPRESSED_RGBA_S3TC_DXT3:
          dwFourCC := FOURCC_DXT3;
        tfCOMPRESSED_RGBA_S3TC_DXT5:
          dwFourCC := FOURCC_DXT5;
        tfCOMPRESSED_LUMINANCE_LATC1:
          dwFourCC := FOURCC_ATI1;
        tfCOMPRESSED_LUMINANCE_ALPHA_LATC2:
          dwFourCC := FOURCC_ATI2;
      else
        Result := False;
      end;
    end;
  end
  else if IsFloatFormat(iFormat) then
  begin
    with DX9header.SurfaceFormat.ddpf do
    begin
      dwFlags := DDPF_FOURCC;
      case iFormat of
        tfINTENSITY_FLOAT16, tfLUMINANCE_FLOAT16, tfR16F:
          dwFourCC := FOURCC_R16F;
        tfRGBA_FLOAT16:
          dwFourCC := FOURCC_A16B16G16R16F;
        tfINTENSITY_FLOAT32, tfLUMINANCE_FLOAT32, tfR32F:
          dwFourCC := FOURCC_R32F;
        tfLUMINANCE_ALPHA_FLOAT16, tfRG16F:
          dwFourCC := FOURCC_G16R16F;
        tfLUMINANCE_ALPHA_FLOAT32, tfRG32F:
          dwFourCC := FOURCC_G32R32F;
        tfRGBA_FLOAT32:
          dwFourCC := FOURCC_A32B32G32R32F
      else
        Result := False;
      end;
    end;
  end
  else
    with DX9header.SurfaceFormat.ddpf do
    begin
      dwFourCC := 0;
      dwRGBBitCount := bpe * 8;
      case bpe of
        1:
          begin
            for i := 0 to High(cImageDataFormat8bits) do
              if (cImageDataFormat8bits[i].colorFormat = colorFormat) and
                (cImageDataFormat8bits[i].TexFormat = iFormat) and
                (cImageDataFormat8bits[i].dType = dataType) then
              begin
                dwFlags := cImageDataFormat8bits[i].ColorFlag;
                dwRBitMask := cImageDataFormat8bits[i].RBits;
                dwGBitMask := cImageDataFormat8bits[i].GBits;
                dwBBitMask := cImageDataFormat8bits[i].BBits;
                dwRGBAlphaBitMask := cImageDataFormat8bits[i].ABits;
                Break;
              end;
          end;

        2:
          begin
            for i := 0 to High(cImageDataFormat16bits) do
              if (cImageDataFormat16bits[i].colorFormat = colorFormat) and
                (cImageDataFormat16bits[i].TexFormat = iFormat) and
                (cImageDataFormat16bits[i].dType = dataType) then
              begin
                dwFlags := cImageDataFormat16bits[i].ColorFlag;
                dwRBitMask := cImageDataFormat16bits[i].RBits;
                dwGBitMask := cImageDataFormat16bits[i].GBits;
                dwBBitMask := cImageDataFormat16bits[i].BBits;
                dwRGBAlphaBitMask := cImageDataFormat16bits[i].ABits;
                Break;
              end;
          end;

        3:
          begin
            for i := 0 to High(cImageDataFormat24bits) do
              if (cImageDataFormat24bits[i].colorFormat = colorFormat) and
                (cImageDataFormat24bits[i].TexFormat = iFormat) and
                (cImageDataFormat24bits[i].dType = dataType) then
              begin
                dwFlags := cImageDataFormat24bits[i].ColorFlag;
                dwRBitMask := cImageDataFormat24bits[i].RBits;
                dwGBitMask := cImageDataFormat24bits[i].GBits;
                dwBBitMask := cImageDataFormat24bits[i].BBits;
                dwRGBAlphaBitMask := cImageDataFormat24bits[i].ABits;
                Break;
              end;
          end;

        4:
          begin
            for i := 0 to High(cImageDataFormat32bits) do
              if (cImageDataFormat32bits[i].colorFormat = colorFormat) and
                (cImageDataFormat32bits[i].TexFormat = iFormat) and
                (cImageDataFormat32bits[i].dType = dataType) then
              begin
                dwFlags := cImageDataFormat32bits[i].ColorFlag;
                dwRBitMask := cImageDataFormat32bits[i].RBits;
                dwGBitMask := cImageDataFormat32bits[i].GBits;
                dwBBitMask := cImageDataFormat32bits[i].BBits;
                dwRGBAlphaBitMask := cImageDataFormat32bits[i].ABits;
                Break;
              end;
          end;

      else
        Result := False;
      end; // of case
    end;

end;

//---------------------------------------------------------------------------------------------

function FindDDSCompatibleDataFormat(const iFormat: TGLinternalFormat; out colorFormat: Cardinal;
  out dataType: Cardinal): Boolean;
var
  i: Integer;
begin
  Result := False;
  // 32 bits data format
  for i := 0 to High(cImageDataFormat32bits) do
    if cImageDataFormat32bits[i].TexFormat = iFormat then
    begin
      colorFormat := cImageDataFormat32bits[i].colorFormat;
      dataType := cImageDataFormat32bits[i].dType;
      Result := True;
      exit;
    end;
  // 24 bits data format
  for i := 0 to High(cImageDataFormat24bits) do
    if cImageDataFormat24bits[i].TexFormat = iFormat then
    begin
      colorFormat := cImageDataFormat24bits[i].colorFormat;
      dataType := cImageDataFormat24bits[i].dType;
      Result := True;
      exit;
    end;
  // 16 bits data format
  for i := 0 to High(cImageDataFormat16bits) do
    if cImageDataFormat16bits[i].TexFormat = iFormat then
    begin
      colorFormat := cImageDataFormat16bits[i].colorFormat;
      dataType := cImageDataFormat16bits[i].dType;
      Result := True;
      exit;
    end;
  // 8 bits data format
  for i := 0 to High(cImageDataFormat8bits) do
    if cImageDataFormat8bits[i].TexFormat = iFormat then
    begin
      colorFormat := cImageDataFormat8bits[i].colorFormat;
      dataType := cImageDataFormat8bits[i].dType;
      Result := True;
      exit;
    end;
end;

end.
